#ifndef XLCOMM_NET_CHANNEL_H_
#define XLCOMM_NET_CHANNEL_H_

#include <functional>
#include <memory>
#include <string>

#include "xlcomm/base/date_time.h"
#include "xlcomm/base/logger.h"
#include "xlcomm/net/event_loop.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {
namespace net {

// IO事件分发(dispatch) 调相应文件描述符(fd)的回调函数
// 每个Channel对象只运行于一个EventLoop线程，只负责一个fd的事件分发，但它不负责关闭这个fd
// Channel对象在析构之前必须调Remove，避免空悬指针
class Channel : noncopyable {
 public:
  using EventCallback = std::function<void()>;
  using ReadCallback = std::function<void(Timestamp)>;
  enum PollStatus { kStatusInit, kStatusAdded, kStatusDeleted };

  // fd可以是socket/eventfd/timerfd/signalfd
  Channel(EventLoop* loop, int fd);
  ~Channel();

  // 监听可读事件
  void EnableReading();
  // 取消监听可读事件
  void DisableReading();
  // 监听可写事件
  void EnableWriting();
  // 取消监听可写事件
  void DisableWriting();
  // 取消监听所有事件
  void DisableAll();
  // 是否监听了可读事件
  bool IsEnableReading() const { return interested_events_ & kReadEvent; }
  // 是否监听了可写事件
  bool IsEnableWriting() const { return interested_events_ & kWriteEvent; }
  // 是否取消监听了所有事件
  bool IsNoneEvent() const { return interested_events_ == kNoneEvent; }

  // 移除Channel的监听
  void Remove();

  // 处理IO事件
  void HandleEvent(Timestamp recv_time);

  // 绑定shared_ptr为weak_ptr，防止调用HandleEvent过程中被析构
  void Tie(const std::shared_ptr<void>& obj);

  // 注册读回调函数，收到可读事件时触发回调
  void set_read_callback(ReadCallback cb) { read_callback_ = std::move(cb); }
  // 注册写回调函数，收到可写事件时触发回调
  void set_write_callback(EventCallback cb) { write_callback_ = std::move(cb); }
  // 注册关闭回调函数，收到意外关闭事件时触发回调
  void set_close_callback(EventCallback cb) { close_callback_ = std::move(cb); }
  // 注册出错回调函数，收到出错事件时触发回调
  void set_error_callback(EventCallback cb) { error_callback_ = std::move(cb); }

  EventLoop* loop() const { return loop_; }
  int fd() const { return fd_; }
  int interested_events() const { return interested_events_; }
  int triggered_events() const { return triggered_events_; }
  PollStatus status() const { return status_; }

  void set_triggered_events(int events) { triggered_events_ = events; }
  void set_status(PollStatus status) { status_ = status; }

  // for debug
  std::string InterestedEventsToString() const {
    return EventsToString(interested_events_);
  }
  std::string TriggeredEventsToString() const {
    return EventsToString(triggered_events_);
  }

 private:
  static const int kNoneEvent;
  static const int kReadEvent;
  static const int kWriteEvent;

  // 更新Channel监听的IO事件
  void Update();
  // 在持有的情况下处理IO事件
  void HandleEventWithShared(Timestamp recv_time);

  // 事件转字符串
  static std::string EventsToString(int events);

  EventLoop* loop_;
  const int fd_;
  int interested_events_;
  int triggered_events_;
  PollStatus status_;
  std::weak_ptr<void> tie_;
  bool tied_;
  bool event_handling_;
  bool added_to_loop_;
  ReadCallback read_callback_;
  EventCallback write_callback_;
  EventCallback close_callback_;
  EventCallback error_callback_;
};

}  // namespace net
}  // namespace xlcomm

#endif  // XLCOMM_NET_CHANNEL_H_